Italiano

Sblocca la potenza dei micro-frontend con JavaScript Module Federation in Webpack 5. Impara a costruire applicazioni web scalabili, manutenibili e indipendenti.

JavaScript Module Federation con Webpack 5: Una Guida Completa ai Micro-frontend

Nel panorama in continua evoluzione dello sviluppo web, la creazione di applicazioni grandi e complesse può essere un'impresa ardua. Le architetture monolitiche tradizionali spesso portano a tempi di sviluppo prolungati, colli di bottiglia nel deployment e difficoltà nel mantenere la qualità del codice. I micro-frontend sono emersi come un potente pattern architetturale per affrontare queste sfide, consentendo ai team di costruire e distribuire parti indipendenti di un'applicazione web più grande. Una delle tecnologie più promettenti per implementare i micro-frontend è la JavaScript Module Federation, introdotta in Webpack 5.

Cosa sono i Micro-frontend?

I micro-frontend sono uno stile architetturale in cui un'applicazione frontend viene scomposta in unità più piccole e indipendenti, che possono essere sviluppate, testate e distribuite autonomamente da team diversi. Ogni micro-frontend è responsabile di uno specifico dominio di business o di una funzionalità, e vengono composti insieme a runtime per formare l'interfaccia utente completa.

Pensatela come un'azienda: invece di avere un unico gigantesco team di sviluppo, avete più team più piccoli che si concentrano su aree specifiche. Ogni team può lavorare in modo indipendente, consentendo cicli di sviluppo più rapidi e una manutenzione più semplice. Considerate una grande piattaforma di e-commerce come Amazon; team diversi potrebbero gestire il catalogo prodotti, il carrello, il processo di checkout e la gestione degli account utente. Questi potrebbero essere tutti micro-frontend indipendenti.

Vantaggi dei Micro-frontend:

Sfide dei Micro-frontend:

Cos'è la JavaScript Module Federation?

La JavaScript Module Federation è una funzionalità di Webpack 5 che consente di condividere codice tra applicazioni JavaScript compilate separatamente a runtime. Permette di esporre parti della propria applicazione come "moduli" che possono essere consumati da altre applicazioni, senza la necessità di pubblicarli su un repository centrale come npm.

Pensate alla Module Federation come a un modo per creare un ecosistema federato di applicazioni, in cui ogni applicazione può contribuire con le proprie funzionalità e consumare funzionalità da altre applicazioni. Questo elimina la necessità di dipendenze in fase di build e consente deployment veramente indipendenti.

Ad esempio, un team che si occupa del design system può esporre componenti UI come moduli, e diversi team applicativi possono consumare questi componenti direttamente dall'applicazione del design system, senza doverli installare come pacchetti npm. Quando il team del design system aggiorna i componenti, le modifiche si riflettono automaticamente in tutte le applicazioni che li consumano.

Concetti Chiave nella Module Federation:

Configurare la Module Federation con Webpack 5: Una Guida Pratica

Vediamo un esempio pratico di configurazione della Module Federation con Webpack 5. Creeremo due semplici applicazioni: un'applicazione Host e un'applicazione Remote. L'applicazione Remote esporrà un componente, e l'applicazione Host lo consumerà.

1. Setup del Progetto

Create due directory separate per le vostre applicazioni: `host` e `remote`.

```bash mkdir host remote cd host npm init -y npm install webpack webpack-cli webpack-dev-server html-webpack-plugin --save-dev npm install react react-dom cd ../remote npm init -y npm install webpack webpack-cli webpack-dev-server html-webpack-plugin --save-dev npm install react react-dom ```

2. Configurazione dell'Applicazione Remote

Nella directory `remote`, create i seguenti file:

src/index.js:

```javascript import React from 'react'; import ReactDOM from 'react-dom/client'; import RemoteComponent from './RemoteComponent'; const App = () => (

Remote Application

); const root = ReactDOM.createRoot(document.getElementById('root')); root.render(); ```

src/RemoteComponent.jsx:

```javascript import React from 'react'; const RemoteComponent = () => (

Questo è un Componente Remoto!

Renderizzato dall'Applicazione Remote.

); export default RemoteComponent; ```

webpack.config.js:

```javascript const HtmlWebpackPlugin = require('html-webpack-plugin'); const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin'); const path = require('path'); module.exports = { entry: './src/index', mode: 'development', devServer: { port: 3001, static: { directory: path.join(__dirname, 'dist'), }, }, output: { publicPath: 'auto', }, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-react', '@babel/preset-env'], }, }, }, ], }, plugins: [ new ModuleFederationPlugin({ name: 'remote', filename: 'remoteEntry.js', exposes: { './RemoteComponent': './src/RemoteComponent', }, shared: { react: { singleton: true, eager: true }, 'react-dom': { singleton: true, eager: true }, }, }), new HtmlWebpackPlugin({ template: './public/index.html', }), ], resolve: { extensions: ['.js', '.jsx'], }, }; ```

Create `public/index.html` con una struttura HTML di base. L'importante è `

`

3. Configurazione dell'Applicazione Host

Nella directory `host`, create i seguenti file:

  • `src/index.js`: Punto di ingresso per l'applicazione.
  • `webpack.config.js`: File di configurazione di Webpack.

src/index.js:

```javascript import React, { Suspense } from 'react'; import ReactDOM from 'react-dom/client'; const RemoteComponent = React.lazy(() => import('remote/RemoteComponent')); const App = () => (

Host Application

Caricamento Componente Remoto in corso...
}>
); const root = ReactDOM.createRoot(document.getElementById('root')); root.render(); ```

webpack.config.js:

```javascript const HtmlWebpackPlugin = require('html-webpack-plugin'); const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin'); const path = require('path'); module.exports = { entry: './src/index', mode: 'development', devServer: { port: 3000, static: { directory: path.join(__dirname, 'dist'), }, }, output: { publicPath: 'auto', }, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-react', '@babel/preset-env'], }, }, }, ], }, plugins: [ new ModuleFederationPlugin({ name: 'host', remotes: { remote: 'remote@http://localhost:3001/remoteEntry.js', }, shared: { react: { singleton: true, eager: true }, 'react-dom': { singleton: true, eager: true }, }, }), new HtmlWebpackPlugin({ template: './public/index.html', }), ], resolve: { extensions: ['.js', '.jsx'], }, }; ```

Create `public/index.html` con una struttura HTML di base (simile all'app remote). L'importante è `

`

4. Installare Babel

In entrambe le directory `host` e `remote`, installate le dipendenze di Babel:

```bash npm install --save-dev @babel/core @babel/preset-env @babel/preset-react babel-loader ```

5. Eseguire le Applicazioni

In entrambe le directory `host` e `remote`, aggiungete il seguente script a `package.json`:

```json "scripts": { "start": "webpack serve" } ```

Ora, avviate entrambe le applicazioni:

```bash cd remote npm start cd ../host npm start ```

Aprite il vostro browser e navigate a `http://localhost:3000`. Dovreste vedere l'applicazione Host con il Componente Remoto renderizzato al suo interno.

Spiegazione delle Opzioni di Configurazione Chiave:

Tecniche Avanzate di Module Federation

La Module Federation offre molte funzionalità avanzate che possono aiutarvi a costruire architetture a micro-frontend ancora più sofisticate.

Remotes Dinamici

Invece di codificare gli URL delle applicazioni remote nella configurazione di Webpack, è possibile caricarli dinamicamente a runtime. Ciò consente di aggiornare facilmente la posizione delle applicazioni remote senza dover ricompilare l'applicazione host.

Ad esempio, potreste memorizzare gli URL delle applicazioni remote in un file di configurazione o in un database e caricarli dinamicamente usando JavaScript.

```javascript // In webpack.config.js remotes: { remote: `promise new Promise(resolve => { const urlParams = new URLSearchParams(window.location.search); const remoteUrl = urlParams.get('remote'); // Supponiamo che remoteUrl sia qualcosa come 'http://localhost:3001/remoteEntry.js' const script = document.createElement('script'); script.src = remoteUrl; script.onload = () => { // la chiave della module federation è che l'app remota è // disponibile usando il nome nel remote resolve(window.remote); }; document.head.appendChild(script); })`, }, ```

Ora potete caricare l'app host con un parametro di query `?remote=http://localhost:3001/remoteEntry.js`

Moduli Condivisi Versionati

La Module Federation può gestire automaticamente il versionamento e la deduplicazione dei moduli condivisi per garantire che venga caricata una sola versione compatibile di ciascun modulo. Questo è particolarmente importante quando si ha a che fare con applicazioni grandi e complesse che hanno molte dipendenze.

È possibile specificare l'intervallo di versioni di ciascun modulo condiviso nella configurazione di Webpack.

```javascript // In webpack.config.js shared: { react: { singleton: true, eager: true, requiredVersion: '^18.0.0' }, 'react-dom': { singleton: true, eager: true, requiredVersion: '^18.0.0' }, }, ```

Loader di Moduli Personalizzati

La Module Federation consente di definire loader di moduli personalizzati che possono essere utilizzati per caricare moduli da diverse fonti o in formati diversi. Questo può essere utile per caricare moduli da una CDN o da un registro di moduli personalizzato.

Condivisione dello Stato tra Micro-frontend

Una delle sfide delle architetture a micro-frontend è la condivisione dello stato tra i diversi micro-frontend. Ci sono diversi approcci che si possono adottare per affrontare questa sfida:

Best Practice per l'Implementazione di Micro-frontend con Module Federation

Ecco alcune best practice da tenere a mente quando si implementano micro-frontend con Module Federation:

Esempi Reali di Module Federation in Azione

Sebbene i casi di studio specifici siano spesso confidenziali, ecco alcuni scenari generalizzati in cui la Module Federation può essere incredibilmente utile:

Conclusione

La JavaScript Module Federation in Webpack 5 fornisce un modo potente e flessibile per costruire architetture a micro-frontend. Consente di condividere codice tra applicazioni JavaScript compilate separatamente a runtime, abilitando deployment indipendenti, diversità tecnologica e una migliore autonomia del team. Seguendo le best practice delineate in questa guida, potete sfruttare la Module Federation per costruire applicazioni web scalabili, manutenibili e innovative.

Il futuro dello sviluppo frontend si sta indubbiamente orientando verso architetture modulari e distribuite. La Module Federation fornisce uno strumento cruciale per la costruzione di questi sistemi moderni, consentendo ai team di creare applicazioni complesse con maggiore velocità, flessibilità e resilienza. Man mano che la tecnologia matura, possiamo aspettarci di vedere emergere casi d'uso ancora più innovativi e best practice.